package com.wdd.myplatform.aop;

import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
@Aspect
@Component
public class IopLogAspect {

    ThreadPoolExecutor logThreadPool = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors()*2,150,60, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(1000000), Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardPolicy());

    @Pointcut("@annotation(com.wdd.myplatform.aop.IopLog)")
    public void aspectCut() {

    }

    @Around("aspectCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();

        // 需要的话接收注解参数
        IopLog iopLog = methodSignature.getMethod().getAnnotation(IopLog.class);
        String code = iopLog.code();
        String className = pjp.getTarget().getClass().getName();
        String methodName = methodSignature.getMethod().getName();
        String methodArgs = StringUtils.EMPTY;
        String execResult = StringUtils.EMPTY;
        Integer execFlag = 1;

        // 参数
        Object[] argsObj = pjp.getArgs();

        Object proceed = null;
        Exception ex = null;
        try {
            proceed = pjp.proceed();
        }  catch (Exception e) {
            execFlag = 0;
            ex = e;
            execResult = e.getMessage();
        }
        if (proceed != null) {
            execResult = JSON.toJSONString(proceed);
        }

        if (argsObj != null) {
            methodArgs = JSON.toJSONString(argsObj);
        }

        //记录日志
        String finalMethodArgs = methodArgs;
        String finalExecResult = execResult;
        Integer finalExecFlag = execFlag;
        logThreadPool.execute(()->{
            saveLog(code, className, methodName, finalMethodArgs, finalExecResult, finalExecFlag);
        });

        // 异常抛出
        if (execFlag == 0) {
            log.error(String.valueOf(ex));
            throw ex;
        }
        return proceed;
    }

    private void saveLog(String code, String className, String methodName, String methodArgs, String execResult, Integer execFlag) {
        // TODO: 2022/3/24 保存数据库
    }
}